﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Grafica3
{
    public class DirectionalLight
    {
        private Vector3 _lightDirection;
        public RenderTarget2D ShadowMap { get; private set; }
        public Vector3 Direction
        {
            get
            { 
                return _lightDirection;
            }
            set
            {
                _lightDirection = value;
            }
        }
        public Color DiffuseColor { get; set; }
        public Color SpecularColor { get; set; }


        public DirectionalLight(Vector3 Direction, Color DiffuseColor, Color SpecularColor)
        {
            _lightDirection = Direction;
            this.DiffuseColor = DiffuseColor;
            this.SpecularColor = SpecularColor;
        }

        public DirectionalLight(Microsoft.Xna.Framework.Graphics.DirectionalLight Light)
        {
            _lightDirection = Light.Direction;
            this.DiffuseColor = new Color(Light.DiffuseColor);
            this.SpecularColor = new Color(Light.SpecularColor);
        }

        public void LoadContent(GraphicsDevice graphic)
        {
            ShadowMap =
                new RenderTarget2D(
                    graphic,
                    graphic.Viewport.Width,
                    graphic.Viewport.Height,
                    false,
                    SurfaceFormat.Single,
                    DepthFormat.Depth24);
        }

        public Matrix CreateLightViewProjectionMatrix(Camera camera)
        {
            // Matrix with that will rotate in points the direction of the light
            Matrix lightRotation = Matrix.CreateLookAt(Vector3.Zero,
                                                       -_lightDirection,
                                                       Vector3.Up);

            // Get the corners of the frustum
            Vector3[] frustumCorners = camera.BoundingFrustum.GetCorners();

            // Transform the positions of the corners into the direction of the light
            for (int i = 0; i < frustumCorners.Length; i++)
            {
                frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightRotation);
            }

            // Find the smallest box around the points
            BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);

            Vector3 boxSize = lightBox.Max - lightBox.Min;
            Vector3 halfBoxSize = boxSize * 0.5f;

            // The position of the light should be in the center of the back
            // pannel of the box. 
            Vector3 lightPosition = lightBox.Min + halfBoxSize;
            lightPosition.Z = lightBox.Min.Z;

            // We need the position back in world coordinates so we transform 
            // the light position by the inverse of the lights rotation
            lightPosition = Vector3.Transform(lightPosition,
                                              Matrix.Invert(lightRotation));

            // Create the view matrix for the light
            Matrix lightView = Matrix.CreateLookAt(lightPosition,
                                                   lightPosition - _lightDirection,
                                                   Vector3.Up);

            // Create the projection matrix for the light
            // The projection is orthographic since we are using a directional light
            Matrix lightProjection = Matrix.CreateOrthographic(boxSize.X, boxSize.Y,
                                                               -boxSize.Z, boxSize.Z);

            return lightView * lightProjection;
        }

    }
}
